﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Objects;
using System.Linq;
using System.Web.DomainServices;
using System.Web.DomainServices.LinqToEntities;
using System.Web.Ria;
using System.Web.Ria.ApplicationServices;

namespace ExpenseReport
{
    //DataProvider to expose ExpenseReports and related entities
    [EnableClientAccess]
    public class ExpenseData : LinqToEntitiesDomainService<ExpenseReports>
    {

        /// <summary>
        /// Query method that returns ExpenseReports for the current user and also 
        /// returns the related employee instance.
        /// </summary>
        /// <returns>ExpenseReports for the current employee and also returns the related employee instance.</returns>
        [RequiresAuthentication()]
        public IQueryable<ExpenseReport> GetExpenseReportsForUser()
        {
            return this.Context.ExpenseReport.Include("Employee").Where(e => e.Employee.employee == UserService.Current.User.Name);
        }

        
        /// <summary>
        /// Query method that returns ExpenseReports have been Submitted and are ready for 
        /// Approval (Status is 1)and belong to an employee whose manager is the current user.
        /// </summary>
        /// <returns>ExpenseReports that have been Submitted and are ready for Approval (Status is 1)and 
        /// belong to an employee whose manager is the current employee.
        /// </returns>
        [RequiresRoles("manager")]
        public IQueryable<ExpenseReport> GetExpenseReportsForApproval()
        {
            return this.Context.ExpenseReport.Include("Employee").Where(e => e.Employee.manager == UserService.Current.User.Name && 
                                                                             e.Status == 1);
        }

        /// <summary>
        /// Query method that returns the ExpenseReport for the ID passed and referenced instances.
        /// </summary>
        /// <param name="erId">ID of ExpenseReport to be returned.</param>
        /// <returns>Returns ExpenseReport with ID passed in and that ExpenseReport's associated ExpenseReportDetails
        /// and Employee instances</returns>
        [RequiresAuthentication()]
        public IQueryable<ExpenseReport> GetExpenseReportWithDetails(int erId)
        {
            return this.Context.ExpenseReport.Include("ExpenseReportDetails")
                                             .Include("Employee")
                                             .Where(e => e.id == erId).Take(1);
        }

        /// <summary>
        /// Inserts ExpenseReport.
        /// </summary>
        /// <param name="er">ExpenseReport to insert.</param>
        [RequiresAuthentication()]
        public void InsertExpenseReport(ExpenseReport er)
        {
            Context.AddToExpenseReport(er);
        }

        /// <summary>
        /// Updates an ExpenseReport.
        /// </summary>
        /// <param name="current">Updated ExpenseReport after changes were made.</param>
        /// <param name="original">Original ExpenseReport before any chagnes were made.</param>
        [RequiresAuthentication()]
        public void UpdateExpenseReport(ExpenseReport current, ExpenseReport original)
        {
            Context.AttachAsModified(current, original);
        }

        /// <summary>
        /// Deletes ExpenseReport.
        /// </summary>
        /// <param name="er">ExpenseReport to insert.</param>
        [RequiresAuthentication()]
        public void DeleteExpenseReport(ExpenseReport er)
        {
            //Checks to see it entity instance is attached because an instance cannot be attached twice.
            if (er.EntityState == EntityState.Detached)
            {
                Context.Attach(er);
            }
            Context.DeleteObject(er);
        }

        /// <summary>
        /// Service operation that updates an expense reports status to the submitted state.
        /// </summary>
        /// <param name="er">ExpenseReport being submitted.</param>
        [ServiceOperation]
        [RequiresAuthentication()]
        public void SubmitExpenseReport(ExpenseReport er)
        {
            if (er.Status == 0) //if Status = Not Submitted
            {
                //Checks to see it entity instance is attached because an instance cannot be attached twice.
                if (er.EntityState == System.Data.EntityState.Detached)
                {
                    Context.Attach(er);
                }
                er.Status = 1;
            }
        }

        /// <summary>
        /// Service operation that updates an expense reports status to the approved state.
        /// </summary>
        /// <param name="er">ExpenseReport being approved.</param>
        [ServiceOperation]
        [RequiresRoles("manager")]
        public void ApproveExpenseReport(ExpenseReport er)
        {
            if (er.Status == 1) //if Status = Submitted
            {
                //Checks to see it entity instance is attached because an instance cannot be attached twice.
                if (er.EntityState == System.Data.EntityState.Detached)
                {
                    Context.Attach(er);
                }
                er.Status = 2;
            }
        }

        /// <summary>
        /// Service operation that updates an expense reports status to the rejected state.
        /// </summary>
        /// <param name="er">ExpenseReport being rejected.</param>
        [ServiceOperation]
        [RequiresRoles("manager")]
        public void RejectExpenseReport(ExpenseReport er)
        {
            if (er.Status == 1)
            {
                if (er.EntityState == System.Data.EntityState.Detached)
                {
                    Context.Attach(er);
                }
                er.Status = 0;
            }
        }

        /// <summary>
        /// Query method that returns all expense report details where the expense report was created by
        /// the current users or the current user is the manager of the employee who created the expense report.
        /// </summary>
        /// <returns>All Expense Report Details that the current user has access to.</returns>
        [RequiresAuthentication()]
        public IQueryable<ExpenseReportDetails> GetExpenseReportDetails()
        {
            return this.Context.ExpenseReportDetails.Where(e => e.ExpenseReport.Employee.employee == UserService.Current.User.Name ||
                                                                e.ExpenseReport.Employee.manager == UserService.Current.User.Name);
        }

        /// <summary>
        /// Inserts ExpenseReportDetails.
        /// </summary>
        /// <param name="er">ExpenseReportDetails to insert.</param>
        [RequiresAuthentication()]
        public void InsertExpenseReportDetails(ExpenseReportDetails er)
        {
            Context.AddToExpenseReportDetails(er);
        }

        /// <summary>
        /// Updates an ExpenseReportDetails.
        /// </summary>
        /// <param name="current">Updated ExpenseReportDetails after changes were made.</param>
        /// <param name="original">Original ExpenseReportDetails before any chagnes were made.</param>
        [RequiresAuthentication()]
        public void UpdateExpenseReportDetails(ExpenseReportDetails current, ExpenseReportDetails original)
        {
            Context.AttachAsModified(current, original);
        }

        /// <summary>
        /// Deletes ExpenseReportDetails.
        /// </summary>
        /// <param name="er">ExpenseReportDetails to delete.</param>
        [RequiresAuthentication()]
        public void DeleteExpenseReportDetails(ExpenseReportDetails er)
        {
            if (er.EntityState == System.Data.EntityState.Detached)
            {
                Context.Attach(er);
            }
            Context.DeleteObject(er);
        }

        /// <summary>
        /// Query method to return all Employees.
        /// </summary>
        /// <returns>All Employees</returns>
        [RequiresAuthentication()]
        public IQueryable<Employee> GetEmployees()
        {
            return this.Context.Employee;
        }
    }

}
